#include "TabelMhs.h"
#include "..\cgraphics\CGraphics.h"

// KONSTRUKTOR - DESTRUKTOR
TabelMhs	CreateEmptyTabelMhs() {
	TabelMhs T = NULL;
	return T;
}

AddressMhs	AllocateRecordMhs(string NIM, string Nama, date TglLahir, string KotaAsal) {
	AllocateRecordMhsAdv(NIM, Nama, TglLahir, KotaAsal, NULL);
}

AddressMhs	AllocateRecordMhsAdv(string NIM, string Nama, date TglLahir, string KotaAsal, AddressMhs next) {
	AddressMhs M = (AddressMhs) malloc(sizeof(RecordMhs));
	if(M!=NULL) {
		NIM(M) 		= NIM;
		NAMA(M) 	= Nama;
		TGLLAHIR(M) = TglLahir;
		KOTAASAL(M) = KotaAsal;
		IPK(M)		= TABELMHS_UNDEF_VAL;
		JMLSKS(M)	= TABELMHS_UNDEF_VAL;
		NEXT(M) 	= next;
		OWNERLIST(M)= NULL;
	}
	return M;
}

void 		DeallocateRecordMhs(RecordMhs *Mhs) {
	free(Mhs);
}

// PREDIKAT

bool		IsRecordMhsEqual(AddressMhs A, AddressMhs B) {
	return IsStringEqual(NIM(A),NIM(B));
}

// OPERASI
void		ChangeRecordMhsContent(AddressMhs Mhs, string NIMbaru, string Namabaru, date TglLahirBaru, string KotaAsalBaru) {
		NIM(Mhs) 		= NIMbaru;
		NAMA(Mhs) 		= Namabaru;
		TGLLAHIR(Mhs) 	= TglLahirBaru;
		KOTAASAL(Mhs)	= KotaAsalBaru;
}

int 		GetRecordMhsSize(AddressMhs Mhs) {
	return NIM(Mhs).length + NAMA(Mhs).length + 6 + KOTAASAL(Mhs).length + ((IPK(Mhs)!=TABELMHS_UNDEF_VAL) ? 3 : 0) + ((JMLSKS(Mhs)!=TABELMHS_UNDEF_VAL) ? 2 : 0);
}

void	 	AddRecordMhs(AddressMhs Mhs, TabelMhs *TMhs) {
	if(ISLINKEDLISTEMPTY(*TMhs)) { // Jika kosong
		FIRST(*TMhs) = Mhs;
		NEXT(Mhs) = NULL;
	}
	else if(IsStringLt(NIM(Mhs),NIM(FIRST(*TMhs)))) { // Jika elmt pertama > Mhs
		NEXT(Mhs) = FIRST(*TMhs);
		FIRST(*TMhs) = Mhs;
	}
	else {
		AddressMhs M;
		TRAVERSETOEND(M,FIRST(*TMhs)) 
			if(IsStringLt(NIM(Mhs),NIM(NEXT(M)))) break;
		
		NEXT(Mhs) = NEXT(M);
		NEXT(M) = Mhs;
	}
}

void	 	DestroyRecordMhs(AddressMhs Mhs, TabelMhs *TMhs) {
	if(Mhs==FIRST(*TMhs)) {
		FIRST(*TMhs) = NEXT(Mhs);
	}
	else {
		AddressMhs M;
		TRAVERSETOEND(M,FIRST(*TMhs))
			if(NEXT(M)==Mhs) break;
		
		NEXT(M) = NEXT(NEXT(M));
	}
	DeallocateRecordMhs(Mhs);
}

AddressMhs	SearchRecordMhsByNIM(string NIM, TabelMhs *TMhs) {
	AddressMhs retval;
	if(ISLINKEDLISTEMPTY(*TMhs)) { // Jika kosong
		retval = NULL;
	}
	else if(IsStringEqual(NIM,NIM(FIRST(*TMhs)))) { // Jika elmt pertama memiliki NIM
		retval = FIRST(*TMhs);
	}
	else {
		AddressMhs M;
		TRAVERSETOEND(M,FIRST(*TMhs)) 
			if(IsStringEqual(NIM,NIM(NEXT(M)))) break;
		
		retval = NEXT(M);
	}
	return retval;
}

AddressMhs	SearchRecordMhs(AddressMhs Mhs, TabelMhs *TMhs) {
	AddressMhs retval;
	if(ISLINKEDLISTEMPTY(*TMhs)) { // Jika kosong
		retval = NULL;
	}
	else if(FIRST(*TMhs)==Mhs) { // Jika elmt pertama memiliki NIM
		retval = FIRST(*TMhs);
	}
	else {
		AddressMhs M;
		TRAVERSETOEND(M,FIRST(*TMhs)) 
			if(NEXT(M)==Mhs) break;
		
		retval = NEXT(M);
	}
	return retval;
}

void		AddOwnerToRecordMhs(AddressMhs Mhs, ownerAddress O) {
	AddOwner(&(OWNERLIST(Mhs)), O);
}

bool 		EvaluateQueryTabelMhsPhase2(AddressMhs Mhs, Reader R, string compare, bool *query_succeed) {
	Reader temp = R;
	bool retval = false;
	if(IsStringEqual(temp.argument[0],Kol_NIM)) {
		if(IsStringEqual(compare,CharToString("<"))) {
			retval = IsStringLt(NIM(Mhs),temp.argument[2]);
		}
		else {
			retval = IsStringEqual(NIM(Mhs), temp.argument[2]);
		}
	}
	else if(IsStringEqual(temp.argument[0],Kol_Nama)) {
		if(IsStringEqual(compare,CharToString("<"))) {
			retval = IsStringLt(NAMA(Mhs),temp.argument[2]);
		}
		else {
			retval = IsStringEqual(NAMA(Mhs), temp.argument[2]);
		}
	}
	else if(IsStringEqual(temp.argument[0],Kol_KotaAsal)) {
		if(IsStringEqual(compare,CharToString("<"))) {
			retval = IsStringLt(KOTAASAL(Mhs),temp.argument[2]);
		}
		else {
			retval = IsStringEqual(KOTAASAL(Mhs), temp.argument[2]);
		}
	}
	else if(IsStringEqual(temp.argument[0],Kol_TglLahir)) {
		if(!IsStringDate(temp.argument[2])) {
			StartPrintMsg(); printf("QUERY ERROR : %s bukan tanggal\n",temp.argument[2].s);
			*query_succeed = false;
		}
		else {
			if(IsStringEqual(compare,CharToString("<"))) {
				retval = IsBefore(TGLLAHIR(Mhs),StringToDate(temp.argument[2]));
			}
			else {
				retval = IsEqD(TGLLAHIR(Mhs),StringToDate(temp.argument[2]));
			}
		}
	}
	else if(IsStringEqual(temp.argument[0],Kol_IPK)) {
		if(!IsStringFloat(temp.argument[2])) {
			StartPrintMsg(); printf("QUERY ERROR : %s bukan angka positif\n",temp.argument[2].s);
			*query_succeed = false;
		}
		else {
			if(IsStringEqual(compare,CharToString("<"))) {
				retval = (IPK(Mhs) < StringToFloat(temp.argument[2]));
			}
			else {
				retval = (IPK(Mhs) == StringToFloat(temp.argument[2]));
			}
		}
	}
	else if(IsStringEqual(temp.argument[0],Kol_JmlSKS)) {
		if(!IsStringFloat(temp.argument[2])) {
			StartPrintMsg(); printf("QUERY ERROR : %s bukan angka\n",temp.argument[2].s);
			*query_succeed = false;
		}
		else {
			if(IsStringEqual(compare,CharToString("<"))) {
				retval = (JMLSKS(Mhs) < StringToInt(temp.argument[2]));
			}
			else {
				retval = (JMLSKS(Mhs) == StringToInt(temp.argument[2]));
			}
		}
	}
	else {
		StartPrintMsg(); printf("QUERY ERROR : Kolom tidak terdefinisi!\n");
		retval = false;
		*query_succeed = false;
	}
	return retval;
}

bool 		EvaluateQueryTabelMhs(AddressMhs Mhs, Reader R, bool *query_succeed) {
	// exit jika argument < 3
	if(R.nArgument < 3) {
		StartPrintMsg(); printf("QUERY ERROR : Query tidak lengkap\n");
		*query_succeed = false;
		return false;
	}
	
	*query_succeed = true;

	Reader temp = R;
	bool retval;
	if(IsStringEqual(temp.argument[1],CharToString("<"))) {
		retval = EvaluateQueryTabelMhsPhase2(Mhs, R, temp.argument[1], query_succeed);
	}
	else if(IsStringEqual(temp.argument[1],CharToString("<="))) {
		retval = EvaluateQueryTabelMhsPhase2(Mhs, R, CharToString("<"), query_succeed) || EvaluateQueryTabelMhsPhase2(Mhs, R, CharToString("="), query_succeed);
	}
	else if(IsStringEqual(temp.argument[1],CharToString(">="))) {
		retval = !EvaluateQueryTabelMhsPhase2(Mhs, R, CharToString("<"), query_succeed);
	}
	else if(IsStringEqual(temp.argument[1],CharToString(">"))) {
		retval = !EvaluateQueryTabelMhsPhase2(Mhs, R, CharToString("<"), query_succeed) && !EvaluateQueryTabelMhsPhase2(Mhs, R, CharToString("="), query_succeed);
	}
	else if(IsStringEqual(temp.argument[1],CharToString("=="))) {
		retval = EvaluateQueryTabelMhsPhase2(Mhs, R, CharToString("="), query_succeed);
	}
	else if(IsStringEqual(temp.argument[1],CharToString("!="))) {
		retval = !EvaluateQueryTabelMhsPhase2(Mhs, R, CharToString("="), query_succeed);
	}
	else {
		StartPrintMsg(); printf("QUERY ERROR : Perintah relasional %s tidak dikenali!\n", temp.argument[1].s);
		retval = false;
		*query_succeed = false;
	}
	
	
	if(R.nArgument==3) { // basis  
		return retval;
	}
	else if(IsStringEqual(R.argument[3],CharToString("AND"))) { // rekursi
		DeleteArguments(&temp,0,4);
		return EvaluateQueryTabelMhs(Mhs, temp, query_succeed) && retval;
	}
	else if(IsStringEqual(R.argument[3],CharToString("OR"))) { // rekursi
		DeleteArguments(&temp,0,4);
		return EvaluateQueryTabelMhs(Mhs, temp, query_succeed) || retval;
	}
	else {
		StartPrintMsg(); printf("QUERY ERROR : Perintah relasional %s tidak dikenali!\n", temp.argument[3].s);
		*query_succeed = false;
		return false;
	}
}

int 		CountRecordMhs(TabelMhs T) {
	int c = 0;
	AddressMhs M;
	TRAVERSETOEND2(M,FIRST(T)) c++;
	return c;
}

int			CountNodeRecordMhs(TabelMhs T, nodeAddress N) {
	int c = 0;
	AddressMhs M;
	TRAVERSETOEND2(M,FIRST(T)) 
		if(SearchOwnerByNode(&OWNERLIST(M),N)) c++;
		
	return c;
}

void		DestroyTabelMhs(TabelMhs *T) {
	AddressMhs M;
	TRAVERSETOEND2(M, FIRST(*T)) {
		DestroyRecordMhs(M, &(*T));
	}
	*T = NULL;
}


void		PrintTabelMhs(TabelMhs T) {
	if(ISLINKEDLISTEMPTY(T)) {
		puts("-EMPTY-");
	}
	else {
		PrintTabelMhsHeader(true,true,true,true,true,true); puts("");
		AddressMhs M;
		TRAVERSETOEND(M,FIRST(T)) {
			PrintRecordMhs(M,true,true,true,true,true,true); puts("");
		}	
		
		PrintRecordMhs(M,true,true,true,true,true,true); puts("");
	}
}

void		PrintTabelMhsHeader(bool showNIM, bool showNama, bool showTglLahir, bool showKotaAsal, bool showIPK, bool showSKS) {
	if(showNIM) {
		string s = Kol_NIM;
		printf("%-10s", s.s);
	}
	if(showNama) {
		string s = Kol_Nama;
		printf("%-25s", s.s);
	}
	if(showTglLahir) {
		string s = Kol_TglLahir;
		printf("%-10s", s.s);
	}
	if(showKotaAsal) {
		string s = Kol_KotaAsal;
		printf("%-15s", s.s);
	}
	if(showIPK) {
		string s = Kol_IPK;
		printf("%-5s", s.s);
	}
	if(showSKS) {
		string s = Kol_JmlSKS;
		printf("%-6s", s.s);
	}
}

void		PrintRecordMhs(AddressMhs Mhs, bool showNIM, bool showNama, bool showTglLahir, bool showKotaAsal, bool showIPK, bool showSKS) {
	if(showNIM) printf("%-10s", NIM(Mhs).s);
	if(showNama) printf("%-25s", NAMA(Mhs).s);
	if(showTglLahir) { string s = DateToString(TGLLAHIR(Mhs));  printf("%-10s", s.s); }
	if(showKotaAsal) printf("%-15s", KOTAASAL(Mhs).s);
	if(showIPK) {
		if(IPK(Mhs)==TABELMHS_UNDEF_VAL) {
			printf("%-5s", "NULL");
		}
		else {
			char s[4];
			sprintf(s,"%1.2f",IPK(Mhs));
			printf("%-6s", s);
		}
	}
	if(showSKS){
		if(JMLSKS(Mhs)==TABELMHS_UNDEF_VAL) {
			printf("%-6s", "NULL");
		}
		else printf("%-6d", JMLSKS(Mhs));
	}
}

